/*
 *
 * *******************************************************************
 *   @项目名称: BHex Android
 *   @文件名称: CImageLoader.java
 *   @Date: 11/29/18 3:21 PM
 *   @Author: chenjun
 *   @Copyright（C）: 2018 BlueHelix Inc.   All rights reserved.
 *   注意：本内容仅限于内部传阅，禁止外泄以及用于其他的商业目的.
 *  *******************************************************************
 *
 */

package io.bhex.baselib.images;

import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;

import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration.Builder;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;

import java.io.File;

import io.bhex.baselib.core.CApplication;
import io.bhex.baselib.utils.DebugLog;


public class CImageLoader {
    private static final int SIZE_MB = 1024 * 1024;

    private static final int MEMORY_LOW = 1;

    private static final int MEMORY_MIDDLE = 2;

    private static final int MEMORY_HIGH = 3;

    /**
     * 缓存Options
     */
    private SparseArray<DisplayImageOptions> optionsArray;

    private static class InstanceHolder {
        private static final CImageLoader _instance = new CImageLoader();
    }

    private CImageLoader() {
        optionsArray = new SparseArray<>();
    }

    public static CImageLoader getInstance() {
        return InstanceHolder._instance;
    }

    /**
     * 初始化参数配置
     */
    private void init() {
        if (ImageLoader.getInstance().isInited())
            return;

        Builder imageConfigBuilder = new Builder(CApplication.getInstance())
                .diskCacheFileNameGenerator(new HashCodeFileNameGenerator())//文件名生成器
                .tasksProcessingOrder(QueueProcessingType.FIFO);//图片请求方式，先进先出

        switch (getMemoryLevel()) {
            case MEMORY_LOW:
                imageConfigBuilder.threadPriority(Thread.MIN_PRIORITY)
                        .threadPoolSize(2)//核心线程数
                        .diskCacheSize(30 * SIZE_MB)   //磁盘缓存图片体积
                        .diskCacheFileCount(100)//磁盘缓存图片数量
                        .diskCacheExtraOptions(480, 320, null); //对图片尺寸进行强制限制
                break;
            case MEMORY_MIDDLE:
                imageConfigBuilder.threadPriority(Builder.DEFAULT_THREAD_PRIORITY)
                        .threadPoolSize(Builder.DEFAULT_THREAD_POOL_SIZE)
                        .memoryCacheSize(2 * SIZE_MB)
                        .diskCacheSize(30 * SIZE_MB)
                        .diskCacheFileCount(100);
                break;
            case MEMORY_HIGH:
                imageConfigBuilder.threadPriority(Thread.NORM_PRIORITY)
                        .threadPoolSize(5)
                        .memoryCacheSize((int) (Runtime.getRuntime().maxMemory() / 8))
                        .memoryCacheSizePercentage(20)
                        .diskCacheSize(50 * SIZE_MB)
                        .diskCacheFileCount(150);
                break;
        }

        ImageLoader.getInstance().init(imageConfigBuilder.build());
        ImageLoader.getInstance().handleSlowNetwork(true);
    }

    /**
     * 加载resource资源
     *
     * @param imageView
     * @param resId
     */
    public void loadRes(ImageView imageView, int resId) {
        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .cacheInMemory(false)
                .cacheOnDisk(false)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .build();
        load(imageView, "drawable://" + resId, -1, options, null);
    }

    /**
     * 加载本地文件
     *
     * @param imageView
     * @param filePath
     * @param defResId
     * @param listener
     */
    public void loadFile(ImageView imageView, String filePath, int defResId, ImageLoadingListener listener) {
        load(imageView, "file://" + formatFilePath("file://", filePath), defResId, null, listener);
    }

    /**
     * 加载本地文件
     *
     * @param imageView
     * @param filePath
     * @param defResId
     * @param listener
     */
    public void loadFile(ImageView imageView, String filePath, int defResId, DisplayImageOptions displayImageOptions, ImageLoadingListener listener) {
        load(imageView, "file://" + formatFilePath("file://", filePath), defResId, displayImageOptions, listener);
    }

    /**
     * 从Assets中加载图片
     *
     * @param imageView
     * @param assetPath
     * @param defResId
     * @param listener
     */
    public void loadAssets(ImageView imageView, String assetPath, int defResId, ImageLoadingListener listener) {
        load(imageView, "assets://" + formatFilePath("assets://", assetPath), defResId, null, listener);
    }

    /**
     * 路径截断，获取我们需要的标准路径
     *
     * @param path
     * @param suffix
     * @return
     */
    private String formatFilePath(String suffix, String path) {

        if (TextUtils.isEmpty(path))
            return "";

        String newPath = path.replace(suffix, "");

        while (newPath.charAt(0) == File.separatorChar) {
            newPath = newPath.substring(1, newPath.length());
        }

        return newPath;
    }

    public void load(ImageView imageView, String url) {
        load(imageView, url, -1, getDisplayImageOptions(-1), null);
    }

    public void load(ImageView imageView, String url, int defRes) {
        load(imageView, url, defRes, getDisplayImageOptions(defRes), null);
    }

    public void load(ImageView imageView, String url, int defRes, ImageLoadingListener listener) {
        load(imageView, url, defRes, getDisplayImageOptions(defRes), listener);
    }

    /**
     * @param imageView
     * @param str
     * @param defRes
     * @param imageWidth
     * @param scale      图片高宽比
     */
    public void load(final ImageView imageView, String str, int defRes, int imageWidth, float scale) {
        final ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
        if (layoutParams != null) {
            layoutParams.width = imageWidth;
            layoutParams.height = (int) (imageWidth * scale);
        } else {
            DebugLog.e("layout params shoud not be null!");
        }

        load(imageView, str, defRes, getDisplayImageOptions(defRes), new SimpleImageLoadingListener() {
            @Override
            public void onLoadingCancelled(String imageUri, View view) {
                if (layoutParams != null)
                    imageView.setLayoutParams(layoutParams);
            }

            @Override
            public void onLoadingStarted(String imageUri, View view) {
                if (layoutParams != null)
                    imageView.setLayoutParams(layoutParams);
            }

            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                if (layoutParams != null)
                    imageView.setLayoutParams(layoutParams);
            }
        });
    }

    public void load(ImageView imageView, String url, int defRes,
                     DisplayImageOptions displayImageOptions, ImageLoadingListener listener) {
        if (imageView == null)
            return;

        init();

        if (displayImageOptions == null) {
            displayImageOptions = getDisplayImageOptions(defRes);
        }

        ImageAware imageViewAware = new ImageViewAware(imageView, false);

        if (listener == null) {
            ImageLoader.getInstance().displayImage(url, imageViewAware, displayImageOptions);
        } else {
            ImageLoader.getInstance().displayImage(url, imageViewAware, displayImageOptions, listener);
        }
    }


    public DisplayImageOptions getRoundDisplayImageOptions(int defRes) {
        DisplayImageOptions.Builder builder = getDisplayImageOptionsBuilder(defRes);
        builder.displayer(new RoundedBitmapDisplayer(Integer.MAX_VALUE));
        return builder.build();
    }

    private DisplayImageOptions getDisplayImageOptions(int defRes) {
        int level = getMemoryLevel();
        //这里简单通过一个位移来处理，可能会有问题，但是可能性比较小，除非defRes很多

        //如果两个资源id相差很小，那么左移就会将差异抹平，从而出现bug

        DisplayImageOptions result = optionsArray.get(defRes * 10 + level);
        if (result != null)
            return result;

        DisplayImageOptions.Builder builder = getDisplayImageOptionsBuilder(defRes);

        result = builder.build();

        optionsArray.put(defRes * 10 + level, result);

        return result;
    }

    private DisplayImageOptions.Builder getDisplayImageOptionsBuilder(int defRes) {

        DisplayImageOptions.Builder cacheOnDisk = new DisplayImageOptions.Builder()
                .resetViewBeforeLoading(true)
                .cacheOnDisk(true);

        if (defRes != -1) {//设置默认图片
            cacheOnDisk.showImageOnLoading(defRes);
            cacheOnDisk.showImageOnFail(defRes);
            cacheOnDisk.showImageForEmptyUri(defRes);
        }

        switch (getMemoryLevel()) {
            case MEMORY_LOW:
                cacheOnDisk.imageScaleType(ImageScaleType.EXACTLY)
                        .bitmapConfig(Bitmap.Config.RGB_565);
                break;
            case MEMORY_MIDDLE:
                cacheOnDisk.cacheInMemory(true)
                        .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
                        .bitmapConfig(Bitmap.Config.RGB_565);
                break;
            case MEMORY_HIGH:
                cacheOnDisk.cacheInMemory(true)
                        .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
                        .bitmapConfig(Bitmap.Config.ARGB_8888);
                break;
        }

        return cacheOnDisk;
    }

    /**
     * 获取当前内存的水平，按照经验值进行的一系列设定
     *
     * @return
     */
    public int getMemoryLevel() {
        ActivityManager activityManager = (ActivityManager) CApplication.getInstance().getSystemService(Context.ACTIVITY_SERVICE);
        //系统为APP分配的内存
        int memoryClassInMB = activityManager.getMemoryClass();

        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
        activityManager.getMemoryInfo(memoryInfo);
        //可用内存
        long availMemInMB = (long) (memoryInfo.availMem / 1024f / 1024);

        float f = memoryClassInMB * 1.0f / availMemInMB;

        if (f > 0.5f && availMemInMB < 512 && memoryClassInMB < 96) {
            DebugLog.w("low memory!");
            return MEMORY_LOW;
        } else if (f > 0.5f || availMemInMB <= 512 || memoryClassInMB <= 96) {
            return MEMORY_MIDDLE;
        } else {
            return MEMORY_HIGH;
        }
    }

    /**
     * 优化ListView滑动时的体验
     *
     * @param onScrollListener
     * @return
     */
    public OnScrollListener setScrollListener(OnScrollListener onScrollListener) {
        switch (getMemoryLevel()) {
            case MEMORY_LOW:
                return new PauseOnScrollListener(ImageLoader.getInstance(), true, true, onScrollListener);
            case MEMORY_MIDDLE:
                return new PauseOnScrollListener(ImageLoader.getInstance(), false, true, onScrollListener);
            case MEMORY_HIGH:
                return new PauseOnScrollListener(ImageLoader.getInstance(), false, false, onScrollListener);
        }

        return onScrollListener;
    }

    /**
     * 清除缓存
     */
    public void clearCache() {
        if (!ImageLoader.getInstance().isInited())
            return;

        ImageLoader.getInstance().clearMemoryCache();
        ImageLoader.getInstance().clearDiskCache();
    }

    /**
     * 唤醒ImageLoader进行工作
     */
    public void resume() {
        if (!ImageLoader.getInstance().isInited()) {
            init();
        }

        ImageLoader.getInstance().resume();
    }
}
